package com.netty.client;

import com.alibaba.fastjson2.JSON;
import com.netty.msg.Message;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.ScheduledFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

public class NettyClientHandler extends SimpleChannelInboundHandler<String> {
    private static final Logger log = LoggerFactory.getLogger(NettyClientHandler.class);

    private NettyClientStarter nettyStarter;

    private Channel channel;

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
        log.info("接收到消息:{}", msg);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        ctx.close();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("与服务端断开连接，即将重连...");
        final EventLoop eventLoop = ctx.channel().eventLoop();
        eventLoop.schedule(new Runnable() {
            @Override
            public void run() {
                nettyStarter.doConnect();
            }
        }, 5L, TimeUnit.SECONDS);
        super.channelInactive(ctx);
    }

    /**
     * 空闲心跳机制
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleState state = ((IdleStateEvent) evt).state();
            if (state == IdleState.ALL_IDLE) {// 写空闲时发心跳
                Message heartMsg = new Message();
                heartMsg.setData("this is heart msg,心跳信息223userEventTriggered now:" + System.currentTimeMillis());
                heartMsg.setCommand("heart");
                String sendMsg = JSON.toJSONString(heartMsg);
                log.info("发送心跳");
                log.info("------>消息长度:length:{},byteLeng:{}",sendMsg.length(),sendMsg.getBytes().length);
                ctx.writeAndFlush(sendMsg).addListener(new GenericFutureListener<Future<? super Void>>() {
                    @Override
                    public void operationComplete(Future<? super Void> future) throws Exception {
                        if (future.isSuccess()) {
                            log.info("客户端-消息发送成功");
                        } else {
                            log.error("客户端-消息发送失败", future.cause());
                        }
                    }
                });
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
//        定时心跳机制
        this.channel = ctx.channel();
//        ping(ctx.channel());
    }

    private void ping(Channel channel) {
        ScheduledFuture<?> future = channel.eventLoop().schedule(new Runnable() {
            @Override
            public void run() {
                if (channel.isActive()) {
                    Message heartMsg = new Message();
                    heartMsg.setData("this is heart msg,now:" + System.currentTimeMillis());
                    heartMsg.setCommand("ping");
                    String sendMsg = JSON.toJSONString(heartMsg);
                    log.info("------>消息长度:length:{},byteLeng:{}",sendMsg.length(),sendMsg.getBytes().length);
                    channel.writeAndFlush(sendMsg).addListener(new GenericFutureListener<Future<? super Void>>() {
                        @Override
                        public void operationComplete(Future<? super Void> future) throws Exception {
                            if (future.isSuccess()) {
                                log.info("客户端-消息发送成功");
                            } else {
                                log.error("客户端-消息发送失败", future.cause());
                            }
                        }
                    });
                } else {
                    channel.closeFuture();
                    throw new RuntimeException();
                }
            }
        }, 10L, TimeUnit.SECONDS);
        future.addListener(new GenericFutureListener() {
            @Override
            public void operationComplete(Future future) throws Exception {
                if (future.isSuccess()) {
                    ping(channel);
                }
            }
        });
    }
}
